﻿/***************************************************************************
 * Copyright Andy Brummer 2004-2005
 * 
 * This code is provided "as is", with absolutely no warranty expressed
 * or implied. Any use is at your own risk.
 *
 * This code may be used in compiled form in any way you desire. This
 * file may be redistributed unmodified by any means provided it is
 * not sold for profit without the authors written consent, and
 * providing that this notice and the authors name is included. If
 * the source code in  this file is used in any commercial application
 * then a simple email would be nice.
 * 
 **************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;

using BackupAssurance.Library.Events;

using System.ComponentModel.Composition;
using BackupAssurance.Library.Constants;
using BackupAssurance.Library.Interfaces;
using BackupAssurance.Library.ModelsDB;
using BackupAssurance.Library.Enums;
//using System.Data.SqlTypes;


namespace BackupAssurance
{
    public delegate void TimerElapsedDelegate(object sender, ScheduledEventArg Args);
    public delegate void RunNowDelegate(object sender, ScheduledEventArg Args);
    public delegate void NextJobToRunDelegate(object sender, ScheduledEventArg Args);
    public delegate void ExceptionDelegate(object sender, ExceptionEventArgs e);

    public class ScheduleTimerBase : IDisposable
    {

        [Import(typeof(IfLogger), AllowRecomposition = true, AllowDefault = false)]
        public IfLogger objLog { get; set; }

        public event ExceptionDelegate ErrorEvent;
        public event TimerElapsedDelegate ElapsedEvent;
        public event NextJobToRunDelegate UpdateNextToRunFieldEvent;
        public event RunNowDelegate RunNowEvent;
        public DateTime TimerFireDateTime;

        /// <summary>
        /// This is here to enhance accuracy.  Even if nothing is scheduled the timer sleeps for a maximum of 1 minute.
        /// </summary>
        private static TimeSpan MAX_INTERVAL = new TimeSpan(0, 1, 0);
        private string _ComputerName;
        private Timer _Timer;
        private List<ScheduledTime> _Jobs;
        private DateTime _LastTimeJobsQueued;
        private Boolean _AnyJobsAdded = false;
        private ScheduledTime _chosen;

        public ScheduleTimerBase(string strComputerName)
        {
            _Timer = new Timer();
            _Timer.AutoReset = false;
            _Timer.Elapsed += new ElapsedEventHandler(Timer_Elapsed);
            _LastTimeJobsQueued = DateTime.MaxValue;
            _Jobs = new List<ScheduledTime>();
            _AnyJobsAdded = false;
            _ComputerName = strComputerName;
        }


        public ScheduledTime AddTimedEvent(pcJobAction objitem)
        {
            _AnyJobsAdded = true;
            ScheduledTime objsch = null;
            string output = String.Format("ScheduleTimerBase.AddTimedEvent");
            objLog.WriteLine(output);
            output = String.Format("Loading Job from DB {0}, {1}, {2}, {3} ", objitem.Id, objitem.name, objitem.ScheduleHour, objitem.EveryHowMany);
            objLog.WriteLine(output);
            objsch = DecodeAndLoadRecord(objitem);
            return objsch;
        }

        //load the schedules
        public void AddAllTimedEvent(List<pcJobAction> jobactionsfromdb, List<pcPlugInValue> pluginsfromdb)
        {
            _Jobs = new List<ScheduledTime>();
            _AnyJobsAdded = false;
            ScheduledTime objsch = null;
            string output = String.Format("ScheduleTimerBase.AddAllTimedEvent");
            objLog.WriteLine(output);

            //try to load the applicable appointments
            foreach (pcJobAction objJob in jobactionsfromdb)
            {
                output = String.Format("Loading Job from DB ID {0}, Name {1}, ScheduleHour{2}, EveryHowMany{3} ", objJob.Id, objJob.name, objJob.ScheduleHour, objJob.EveryHowMany);
                objLog.WriteLine(output);
                foreach (pcPlugInValue objPlugIn in pluginsfromdb)
                {
                    if (objPlugIn.pcJobActionId == objJob.Id)
                    {
                        output = String.Format("   to Execute: {0}", objPlugIn.name);
                        objLog.WriteLine(output);
                    }
                }
                objsch = DecodeAndLoadRecord(objJob);
            }

            objLog.WriteLine("Starting the timer.");
            //start the timer
            if (_AnyJobsAdded == true)
            {
                STBStart();
            }
        }

        /// <summary>
        /// Clears out all scheduled jobs.
        /// </summary>
        public void ClearJobs()
        {
            _LastTimeJobsQueued = DateTime.Now;
            _AnyJobsAdded = false;
            _chosen = null;
            _Jobs.Clear();
        }

        public List<ScheduledTime> getScheduledJobs()
        {
            return _Jobs;
            /*
            List<ScheduledTime> ScheduledJobs = new List<ScheduledTime>();
            foreach (ScheduledTime Job in _Jobs)
            {
                ScheduledJobs.Add(Job);
            }
            return ScheduledJobs;
             * */
        }

        public void RemoveJob(ScheduledTime objTime)
        {
            foreach (ScheduledTime Job in _Jobs)
            {
                if (Job._JobAction.Id == objTime._JobAction.Id)
                {
                    _Jobs.Remove(objTime);
                }
            }
        }

        public void RemoveSpecificJob(ScheduledTime objTime, DateTime nextrun)
        {
            foreach (ScheduledTime Job in _Jobs)
            {
                if (Job._JobAction.Id == objTime._JobAction.Id && Job._NextRunDateTime == nextrun)
                {
                    _Jobs.Remove(objTime);
                }
            }
        }


        public void QueueNextEvent(DateTime inStartTime)
        {

            //double update;
            _LastTimeJobsQueued = inStartTime;


            string output = String.Format("ScheduledTimerBase.QueueNextEvent inStartTime: {0} ", inStartTime);
            objLog.WriteLine(output);

            if (_Jobs.Count == 0)
            {
                //create a refresh job, just to recheck the database for schedules a little later.
            }

            foreach (ScheduledTime Job in _Jobs)
            {
                //do one last check, make sure that no job is scheduled to run in the past
                if (Job._NextRunDateTime < DateTime.Now)
                {
                    Job.STNextRunTime(inStartTime);
                    UpdateNextToRunFieldEvent.Invoke(this, new ScheduledEventArg(Job));
                }

                output = String.Format("QueueNextEvent updated execution time {1} for job {0} and ID {2}", Job._JobAction.name, Job._NextRunDateTime, Job._JobAction.Id);
                objLog.WriteLine(output);
            }


            _Jobs.Sort((x, y) => DateTime.Compare(x._NextRunDateTime, y._NextRunDateTime));
            _chosen = _Jobs[0];


            if (_Jobs[0]._NextRunDateTime < DateTime.Now)
            {
                if (_Jobs.Count >= 2)
                {
                    _chosen = _Jobs[1];
                }
            }

            DateTime next = _chosen._NextRunDateTime;
            TimerFireDateTime = next;

            objLog.WriteLine("");
            output = String.Format("SORT SAYS this job is next: {0}", _Jobs[0]._JobAction.name);
            objLog.WriteLine(output);

            output = String.Format("QueueNextEvent FINAL Chosen as lesser ID: {0} [{1}], at {2}", _chosen._JobAction.Id, _chosen._JobAction.name, next);
            objLog.WriteLine(output);

            TimeSpan interval = next - inStartTime;

            if (interval.TotalMilliseconds <= 0)
            {
                interval = new TimeSpan(0, 1, 0);
            }

            _Timer.Interval = interval.TotalMilliseconds;

            if (interval.TotalMilliseconds <= Int32.MaxValue)
            {
                output = String.Format("TIMER START and configured to fire in : {0}", interval.ToString());
                objLog.WriteLine(output);
                _Timer.Start();
            }
            else
            {
                output = String.Format("Couldnt start the timer, the next job is scheduled too far in advanced: {0}", interval.ToString());
                objLog.WriteLine(output);
            }

            output = String.Format("ScheduledTimerBase.QueueNextEvent complete. ", inStartTime);
            objLog.WriteLine(output);
        }



        /// <summary>
        /// Begins executing all assigned jobs at the scheduled times
        /// </summary>
        public void STBStart()
        {
            _LastTimeJobsQueued = DateTime.Now;
            QueueNextEvent(_LastTimeJobsQueued);
        }

        /// <summary>
        /// Halts executing all jobs.  When the timer is restarted all jobs that would have run while the timer was stopped are re-tried.
        /// </summary>
        public void StopTimer()
        {
            objLog.WriteLine("TIMER STOP. ScheduledTimerBase.StopTimer");
            _Timer.Stop();
        }


        private void OnError(DateTime eventTime, ScheduledTime job, Exception e)
        {
            if (ErrorEvent == null)
                return;

            //string output = String.Format("ScheduledTimerBase.OnError EventTime {0}, {1} and throw exception", eventTime, job.ToString());
            //objLog.WriteLine(output);

            try
            {
                ErrorEvent(this, new ExceptionEventArgs(job, e));
            }
            catch (Exception) { }
        }

        private void Timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            Boolean shouldStay = true;

            DateTime executiontime = DateTime.Now;
            objLog.WriteLine("");
            objLog.WriteLine("TIMER FIRED");

            try
            {
                //ElapsedEventArgs e this is all we get from the WINDOWS TIMER, so I need to look it up in the list
                //to know which one was it that fired.
                objLog.WriteLine("TIMER Stopped");
                _Timer.Stop();


                if (_Jobs == null)
                {
                    //no jobs, have the timer fire again in 30 minutes.
                    _Timer.Interval = 1800000;
                    _Timer.Start();
                    return;
                }


                do
                {
                    for (int i = 0; i < _Jobs.Count; i++)
                    {
                        //here try to find the job, if I find it, find the details.  But really just need to 
                        //raise an event to notify whomever cares.
                        //use nextrundatetime, instead of a job id, in case that multiple fire at the same time.

                        try
                        {
                            if (_Jobs[i]._NextRunDateTime <= DateTime.Now + TimeSpan.FromSeconds(2))
                            {
                                objLog.WriteLine("----------------->");
                                string output = String.Format("{2} Running Job ID:{0} [{1}]", _Jobs[i]._JobAction.Id, _Jobs[i]._JobAction.name, DateTime.Now);
                                objLog.WriteLine(output);

                                _Jobs[i]._LastRunTime = DateTime.Now;
                                _LastTimeJobsQueued = DateTime.Now;

                                ElapsedEvent.Invoke(this, new ScheduledEventArg(_Jobs[i]));

                                if (_Jobs[i]._Base == EventTimeBase.RunOnce)
                                {
                                    //remove it, dont update anything in the database.
                                    output = String.Format("RIGHT Now Job [{0}] with ID: {1} Removed.", _Jobs[i]._JobAction.name, _Jobs[i]._JobAction.Id);
                                    objLog.WriteLine(output);
                                    _Jobs.RemoveAt(i);
                                    i = i - 1;
                                }
                                else
                                {
                                    _Jobs[i].STNextRunTime(_LastTimeJobsQueued);
                                    UpdateNextToRunFieldEvent.Invoke(this, new ScheduledEventArg(_Jobs[i]));
                                }
                                shouldStay = false;
                            }
                            else
                            {
                                shouldStay = false;
                            }
                        }
                        catch (Exception ex)
                        {
                            objLog.WriteError(0, "Timer_Elapsed ID:" + _Jobs[i]._JobAction.Id.ToString() + " Error:" + ex.Message + Environment.NewLine + ex.StackTrace);
                            OnError(DateTime.Now, _Jobs[i], ex);
                        }
                    }
                } while (shouldStay);
                objLog.WriteLine("One or more jobs were just triggerred, now calling QueueNextEvent to load the next job into the timer");
            }
            catch (Exception ex)
            {
                objLog.WriteError(0, "Timer_Elapsed " + " Error:" + ex.Message + Environment.NewLine + ex.StackTrace);
                OnError(DateTime.Now, null, ex);
            }
            finally
            {
                QueueNextEvent(executiontime);
            }
        }



        public void Dispose()
        {
            if (_Timer != null)
                _Timer.Dispose();
        }



        private Boolean compareTimerjobToDBjob(List<pcJobAction> jobsfromdb)
        {
            Boolean JobFound = false;
            Boolean werejobsremoved = false;
            string output = "";

            //loop through all the jobs in the timer
            foreach (ScheduledTime Job in _Jobs)
            {
                JobFound = false;
                //loop through all the jobs in the database
                foreach (pcJobAction ja in jobsfromdb)
                {
                    if (ja.Id == Job._JobAction.Id)
                    {
                        JobFound = true;
                    }
                }
                if (JobFound == false)
                {
                    werejobsremoved = true;
                    //disable the job and remove it
                    output = string.Format("Job {0} [{1}] was found to be disabled in the database.  Removing the job from the timer.", Job._JobAction.Id, Job._JobAction.name);
                    objLog.WriteLine(output);
                    RemoveJob(Job);
                    break;
                }
            }

            return werejobsremoved;
        }

        public Boolean compareDBjobToTimerjob(List<pcJobAction> jobsfromdb)
        {
            Boolean JobFound = false;
            Boolean ThisJobUpdated = false;
            Boolean AnyJobUpdatedOnTop = false;
            Boolean AnyJobUpdatedBottom = false;
            Boolean ConsolidatedResponse = false;
            List<ScheduledTime> RunNow = new List<ScheduledTime>();
            string output = "";

            objLog.WriteLine("Looping through all the jobs in the database, and seeing if any jobs in the timer need to change.");


            //loop through all the jobs in the database, and see if the jobs in the timer need to change
            //Loop - all the jobs in the database
            foreach (pcJobAction ja in jobsfromdb)
            {

                JobFound = false;
                //loop through all the jobs in the timer
                foreach (ScheduledTime Job in _Jobs)
                {
                    if (ja.Id == Job._JobAction.Id)
                    {
                        if (ja.RunNow == true)
                        {
                            RunNow.Add(Job);
                        }
                        JobFound = true;
                        //check which fields need to be updated (if any)
                        if (ja.DateOfMonth != Job._JobAction.DateOfMonth) { ThisJobUpdated = true; Job._JobAction.DateOfMonth = ja.DateOfMonth; }
                        if (ja.dayFriday != Job._JobAction.dayFriday) { ThisJobUpdated = true; Job._JobAction.dayFriday = ja.dayFriday; }
                        if (ja.dayMonday != Job._JobAction.dayMonday) { ThisJobUpdated = true; Job._JobAction.dayMonday = ja.dayMonday; }
                        //if (ja.DayOfWeek != Job._JobAction.DayOfWeek) { ThisJobUpdated = true; Job._JobAction.DayOfWeek = ja.DayOfWeek; }
                        if (ja.daySaturday != Job._JobAction.daySaturday) { ThisJobUpdated = true; Job._JobAction.daySaturday = ja.daySaturday; }
                        if (ja.daySunday != Job._JobAction.daySunday) { ThisJobUpdated = true; Job._JobAction.daySunday = ja.daySunday; }
                        if (ja.dayThursday != Job._JobAction.dayThursday) { ThisJobUpdated = true; Job._JobAction.dayThursday = ja.dayThursday; }
                        if (ja.dayTuesday != Job._JobAction.dayTuesday) { ThisJobUpdated = true; Job._JobAction.dayTuesday = ja.dayTuesday; }
                        if (ja.dayWednesday != Job._JobAction.dayWednesday) { ThisJobUpdated = true; Job._JobAction.dayWednesday = ja.dayWednesday; }
                        if (ja.EndDate != Job._JobAction.EndDate) { ThisJobUpdated = true; Job._JobAction.EndDate = ja.EndDate; }
                        if (ja.EveryHowMany != Job._JobAction.EveryHowMany) { ThisJobUpdated = true; Job._JobAction.EveryHowMany = ja.EveryHowMany; }
                        if (ja.ScheduleHour != Job._JobAction.ScheduleHour) { ThisJobUpdated = true; Job._JobAction.ScheduleHour = ja.ScheduleHour; }
                        if (ja.StartDate != Job._JobAction.StartDate) { ThisJobUpdated = true; Job._JobAction.StartDate = ja.StartDate; }
                        if (ja.TypeSchedule != Job._JobAction.TypeSchedule) { ThisJobUpdated = true; Job._JobAction.TypeSchedule = ja.TypeSchedule; }

                        if (ThisJobUpdated)
                        {
                            //updates are needed (at least to this one job)
                            //recalculate the next due date
                            output = string.Format("Job {0}  [{1}] was updated.", ja.Id, ja.name);
                            objLog.WriteLine(output);
                            AnyJobUpdatedOnTop = true;
                            Job.STNextRunTime(DateTime.Now);
                            UpdateNextToRunFieldEvent.Invoke(this, new ScheduledEventArg(Job));
                        }


                    }
                }


                if (JobFound == false)
                {
                    //add the new record to the schedule
                    output = string.Format("Adding Job {0} [{1}] to the timer.", ja.Id, ja.name);
                    objLog.WriteLine(output);

                    AnyJobUpdatedOnTop = true;
                    ScheduledTime objthisjob = AddTimedEvent(ja);

                    if (objthisjob._Base != EventTimeBase.Off)
                    {
                        objthisjob.STNextRunTime(DateTime.Now);
                        UpdateNextToRunFieldEvent.Invoke(this, new ScheduledEventArg(objthisjob));
                    }
                }


            }

            foreach (ScheduledTime item in RunNow)
            {
                //remove the runnow flag
                item._JobAction.RunNow = false;
                RunNowEvent.Invoke(this, new ScheduledEventArg(item));


                //schedule the work
                ScheduledTime objTempCopy = new ScheduledTime("RunOnce", "1,0", item._JobAction, DateTime.Now, false);
                objTempCopy._LastRunTime = DateTime.Now;
                objTempCopy._NextRunDateTime = DateTime.Now + TimeSpan.FromMinutes(2);
                output = string.Format("Job {0} ID:{1} from database is requesting to start RIGHT NOW.  Scheduled to start {2}", item._JobAction.name, item._JobAction.Id, objTempCopy._NextRunDateTime);
                objLog.WriteLine(output);
                _Jobs.Add(objTempCopy);
                AnyJobUpdatedOnTop = true;
                break;
            }

            RunNow.Clear();
            RunNow = null;

            AnyJobUpdatedBottom = compareTimerjobToDBjob(jobsfromdb);

            //if any job was updated, then rechoose the next to run
            if (AnyJobUpdatedOnTop == true || AnyJobUpdatedBottom == true)
            {
                ConsolidatedResponse = true;
                output = string.Format("Changes found between the Database records and the Timer.  Acquiring and scheduling the next job to fire.");
                objLog.WriteLine(output);
            }


            return ConsolidatedResponse;
        }

        private ScheduledTime DecodeAndLoadRecord(pcJobAction objitem)
        {

            //objitem.DateOfMonth, objitem.DayOfWeek, objitem.EveryHowMany, objitem, 
            //objitem.JobScheduleID, objitem.JobScheduleType, objitem.ScheduleHour, objitem.Schedulename, objitem.ServerIP, objitem.dayFriday, 
            //objitem.dayMonday, objitem.daySaturday, objitem.daySunday, objitem.dayThursday, objitem.dayTuesday, objitem.dayWednesday

            //        BySecond = 1,
            //        ByMinute = 2,
            //        Hourly = 3,
            //        Daily = 4,
            //        Weekly = 5,
            //        Monthly = 6,

            ScheduledTime objTempCopy = new ScheduledTime("Off", "0", null, DateTime.MinValue, false);
            DateTime update;
            DateTime nextrun;
            Boolean doAddIt = false;

            if (objitem.RunNow == true)
            {
                objitem.RunNow = false;
                //schedule the work
                objTempCopy = new ScheduledTime("RunOnce", "1,0", objitem, DateTime.Now, false);

                objTempCopy._LastRunTime = DateTime.Now;
                objTempCopy._NextRunDateTime = DateTime.Now + TimeSpan.FromMinutes(2);

                //remove the runnow flag
                RunNowEvent.Invoke(this, new ScheduledEventArg(objTempCopy));

                string output = string.Format("Job {0} ID:{1} Starting, discovered job that needs to run RIGHT NOW.  Scheduled to start {2}", objitem.name, objitem.Id, objTempCopy._NextRunDateTime);
                objLog.WriteLine(output);

                _Jobs.Add(objTempCopy);
                _AnyJobsAdded = true;
            }

            switch (objitem.TypeSchedule)
            {
                case Constants.SCH_BYMINUTE:
                    {

                        string output = String.Format("  we determined that this SCH_BYMINUTE item should added because its today or tomorrow [{0}]", objitem.name);
                        objLog.WriteLine(output);
                        _AnyJobsAdded = true;
                        objTempCopy = new ScheduledTime("ByMinute", objitem.EveryHowMany.ToString() + ",0", objitem, objitem.RunTimeLast, false);
                        _Jobs.Add(objTempCopy);

                    }
                    break;
                case Constants.SCH_HOURLY:
                    {

                        string output = String.Format("  we determined that this SCH_HOURLY item should added because its today or tomorrow [{0}]", objitem.name);
                        objLog.WriteLine(output);
                        objTempCopy = new ScheduledTime("Hourly", objitem.EveryHowMany.ToString() + ",0", objitem, objitem.RunTimeLast, false);
                        _Jobs.Add(objTempCopy);
                        _AnyJobsAdded = true;

                    }
                    break;
                case Constants.SCH_DAILY:
                    {
                        string output = String.Format("  we determined that this SCH_DAILY item should added because it runs daily [{0}]", objitem.name);
                        objLog.WriteLine(output);
                        objTempCopy = new ScheduledTime("Daily", objitem.ScheduleHour.TimeOfDay.ToString(), objitem, objitem.RunTimeLast, false);
                        _Jobs.Add(objTempCopy);
                        _AnyJobsAdded = true;
                    }
                    break;
                case Constants.SCH_WEEKLY:
                    {
                        //it needs number of hours
                        bool ShouldFireAll7Days = AnyDayFieldsUsed(objitem);
                        update = DateTime.Now;
                        objTempCopy = new ScheduledTime("Weekly", "0," + objitem.ScheduleHour.TimeOfDay.ToString(), objitem, objitem.RunTimeLast, ShouldFireAll7Days);
                        _Jobs.Add(objTempCopy);
                        _AnyJobsAdded = true;
                    }

                    break;
                case Constants.SCH_MONTHLYONDATE:
                    {
                        //needs a specific DATE and Time (i.e. 5th, 12:00pm)                    
                        if (DateTime.Now.Date.Day == objitem.DateOfMonth)
                        {
                            string output = String.Format("  we determined that this SCH_MONTHLYONDATE item should added because today is {0} day of month [{1}]", objitem.DateOfMonth, objitem.name);
                            objLog.WriteLine(output);
                            objTempCopy = new ScheduledTime("Monthly", objitem.DateOfMonth.ToString() + "," + objitem.ScheduleHour.TimeOfDay.ToString(), objitem, objitem.RunTimeLast, false);
                            _Jobs.Add(objTempCopy);
                            _AnyJobsAdded = true;
                        }
                        else
                        {
                            string output = String.Format("  SCH_MONTHLYONDATE failed date check [{0}]", objitem.name);
                            objLog.WriteLine(output);
                        }

                    }
                    break;
                case Constants.SCH_ONCE:
                    //needs a date and a time 
                    {
                        string output = String.Format("  we determined that this SCH_ONCE item should added because its today or tomorrow [{0}]", objitem.name);
                        objLog.WriteLine(output);
                        objTempCopy = new ScheduledTime("Once", TimeSpan.Zero.ToString(), objitem, DateTime.Now, false);
                        objTempCopy._LastRunTime = objitem.StartDate;
                        objTempCopy._NextRunDateTime = new DateTime(objitem.StartDate.Year, objitem.StartDate.Month, objitem.StartDate.Day, objitem.ScheduleHour.Hour, objitem.ScheduleHour.Minute, objitem.ScheduleHour.Second) + TimeSpan.FromMinutes(2);
                        _Jobs.Add(objTempCopy);
                        _AnyJobsAdded = true;
                    }
                    break;
                default:
                    break;
            }

            return objTempCopy;
        }

        private bool ShouldWeeklyEventRunThisDate(DateTime testDate, pcJobAction job)
        {
            bool shouldruntoday = false;

            if ((testDate.DayOfWeek == DayOfWeek.Sunday) && (job.daySunday == true))
            {
                shouldruntoday = true;
            }
            if ((testDate.DayOfWeek == DayOfWeek.Monday) && (job.dayMonday == true))
            {
                shouldruntoday = true;
            }
            if ((testDate.DayOfWeek == DayOfWeek.Tuesday) && (job.dayTuesday == true))
            {
                shouldruntoday = true;
            }
            if ((testDate.DayOfWeek == DayOfWeek.Wednesday) && (job.dayWednesday == true))
            {
                shouldruntoday = true;
            }
            if ((testDate.DayOfWeek == DayOfWeek.Thursday) && (job.dayThursday == true))
            {
                shouldruntoday = true;
            }
            if ((testDate.DayOfWeek == DayOfWeek.Friday) && (job.dayFriday == true))
            {
                shouldruntoday = true;
            }
            if ((testDate.DayOfWeek == DayOfWeek.Saturday) && (job.daySaturday == true))
            {
                shouldruntoday = true;
            }

            return shouldruntoday;
        }
        private void _Error(object Sender, ExceptionEventArgs Args)
        {
            string StrError = "";
            Exception e = Args.Error;
            while (e != null)
            {
                StrError += e.Message + Environment.NewLine + e.StackTrace + Environment.NewLine + "-----------------------------" + Environment.NewLine + "";
                e = e.InnerException;
            }
            //MessageBox.Show(StrError);
            //Close();
        }

        private Boolean AnyDayFieldsUsed(pcJobAction objitem)
        {

            if ((objitem.dayFriday) || (objitem.dayMonday) || (objitem.daySaturday) || (objitem.daySunday) || (objitem.dayThursday) || (objitem.dayTuesday) || (objitem.dayWednesday))
            {
                return false;
            }
            else
            {
                return true;
            }


        }

        private Boolean isToday(pcJobAction objitem)
        {
            //check just today
            if ((DateTime.Now.DayOfWeek == DayOfWeek.Sunday) && (objitem.daySunday == true)) { return true; }
            if ((DateTime.Now.DayOfWeek == DayOfWeek.Monday) && (objitem.dayMonday == true)) { return true; }
            if ((DateTime.Now.DayOfWeek == DayOfWeek.Tuesday) && (objitem.dayTuesday == true)) { return true; }
            if ((DateTime.Now.DayOfWeek == DayOfWeek.Wednesday) && (objitem.dayWednesday == true)) { return true; }
            if ((DateTime.Now.DayOfWeek == DayOfWeek.Thursday) && (objitem.dayThursday == true)) { return true; }
            if ((DateTime.Now.DayOfWeek == DayOfWeek.Friday) && (objitem.dayFriday == true)) { return true; }
            if ((DateTime.Now.DayOfWeek == DayOfWeek.Saturday) && (objitem.daySaturday == true)) { return true; }

            return false;
        }


        private Boolean itsPrettyClose(pcJobAction objitem)
        {
            //I am hoping that my home-made second-check will help me ensure that an appointment is not missed for being to close to midnight, etc
            Boolean shouldBeOnTomorrow = false;

            //check just today
            if ((DateTime.Now.DayOfWeek == DayOfWeek.Sunday) && (objitem.dayMonday == true)) { shouldBeOnTomorrow = true; }
            if ((DateTime.Now.DayOfWeek == DayOfWeek.Monday) && (objitem.dayTuesday == true)) { shouldBeOnTomorrow = true; }
            if ((DateTime.Now.DayOfWeek == DayOfWeek.Tuesday) && (objitem.dayWednesday == true)) { shouldBeOnTomorrow = true; }
            if ((DateTime.Now.DayOfWeek == DayOfWeek.Wednesday) && (objitem.dayThursday == true)) { shouldBeOnTomorrow = true; }
            if ((DateTime.Now.DayOfWeek == DayOfWeek.Thursday) && (objitem.dayFriday == true)) { shouldBeOnTomorrow = true; }
            if ((DateTime.Now.DayOfWeek == DayOfWeek.Friday) && (objitem.daySaturday == true)) { shouldBeOnTomorrow = true; }
            if ((DateTime.Now.DayOfWeek == DayOfWeek.Saturday) && (objitem.daySunday == true)) { shouldBeOnTomorrow = true; }

            if (shouldBeOnTomorrow == true)
            {
                if (DateTime.Now.Hour > 21)
                {
                    return true;
                }
            }

            return false;
        }
        public void Reset()
        {
            string output = String.Format("ScheduleTimerBase.Reset");
            objLog.WriteLine(output);
            StopTimer();
            ClearJobs();
        }

    }
}
